package com.ynhenc.pta.routeRank.impl;

import com.ynhenc.pta.routeRank.*;

import java.io.*;

public abstract class RouteRankImpl extends ComLib_PTA implements RouteRank {
	
	public abstract String getCode()  ;
	
	public RouteResult getRouteResultShortest() {
		return this.getRouteResult( 0 );
	}
	public RouteResult getRouteResultGreen01() {
		return this.getRouteResult( 1 );
	}
	public RouteResult getRouteResultGreen012() {
		return this.getRouteResult( 2 );
	}

	final public String getVersion() {
		return RouteRankImpl.getProgramVersion();
	}

	public static String getProgramVersion() {
		return SysConfPta.PROGRRAM_NAME;
	}

	final public void toKML(File file) throws Exception {
		RouteRank routeRank = this;

		StringBuffer buff = new StringBuffer();

		routeRank.toKml(buff);

		FileOutputStream fos = new FileOutputStream(file);
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, "UTF-8"));
		writer.write(buff.toString());
		writer.flush();
		fos.flush();
		fos.close();
	}

	final public String getName() {
		return this.getCode() + ": " +  this.getRouteRequest().getScenario().getName();
	}

	final public Scenario getScenario() {
		return this.getRouteRequest().getScenario();
	}

	final public String getDescription() {
		RouteRequest req = this.getRouteRequest();
		return "traffic:" + req.isTrafficGood() 
		+ ", " + req.getNodeStart() + ":" + req.getNodeEnd() 
		;
	} 

	final public void toKml(StringBuffer buff) {

		buff.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		buff.append("<kml xmlns=\"http://earth.google.com/kml/2.2\">");
		buff.append(NL);
		buff.append("<Document>");
		buff.append(NL);
		buff.append("<name>");
		buff.append("routeRank_" + this.getName());
		buff.append("</name>");
		buff.append(NL);
		buff.append("<description>");
		buff.append(this.getDescription());
		buff.append("</description>");

		if (true) { // kml style save
			TransitType.WALK.toKml(buff);
			buff.append(NL);
			TransitType.BIKE.toKml(buff);
			buff.append(NL);
			TransitType.BUS.toKml(buff);
			buff.append(NL);
			TransitType.AUTOMOBILE.toKml(buff);
			buff.append(NL);
			TransitType.SUBWAY.toKml(buff);
		} // end of saving kml style

		buff.append(NL);

		// route result save
		RouteResult routeResult;
		for (int i = 0, iLen = this.getCountRoutResult(); i < iLen; i++) {
			routeResult = this.getRouteResult(i);
			routeResult.toKml(buff);
			buff.append(NL);
		}
		// end of route result save

		buff.append("</Document>");
		buff.append("</kml>");
	}

	final public void addRouteResult(RouteResultImpl routeResult) {
		this.routeResultList.add(routeResult);
	}

	final public int getCountRoutResult() {
		return this.routeResultList.size();
	}

	final public RouteResult getRouteResult(int index) {
		return this.routeResultList.get(index);
	}

	final public SectionList getSectionList(StartEndNode seNode, RouteRequest req) throws Exception {

		SectionListGetter sectionGetter = new SectionListAutoMobile();

		final TransitType transitType = seNode.getTransitType();

		if (transitType == TransitType.BUS) {
			sectionGetter = new SectionListBus(req);
		} else if (transitType == TransitType.SUBWAY) {
			sectionGetter = new SectionListSubway(req);
		} else if (transitType == TransitType.BIKE) {
			sectionGetter = new SectionListBike();
		} else if (transitType == TransitType.WALK) {
			sectionGetter = new SectionListWalk();
		}

		return sectionGetter.getSectionList(seNode);
	}

	public final RouteResultImpl getRouteResult(RouteRequest routeRequest, RouteSearchType routeSearchType, StartEndNodeList seNodeList) throws Exception {

		SectionList sectionList = new SectionList();
		RouteResultImpl routeResult = new RouteResultImpl(sectionList, routeSearchType);

		for (int i = 0, iLen = seNodeList.size(); i < iLen; i++) {
			StartEndNode seNode = seNodeList.get(i);
			SectionList sectionListLocal = this.getSectionList(seNode, routeRequest);
			routeResult.addSectionList( sectionListLocal );
			//sectionList.addList(sectionListLocal);
		}

		return routeResult;
	} 

	public abstract RouteResultImpl getRouteResult_Shortest(RouteRequest routeRequest) throws Exception;

	public abstract RouteResultImpl getRouteResult_Green_01(RouteRequest routeRequest) throws Exception;

	public abstract RouteResultImpl getRouteResult_Green_02(RouteRequest routeRequest) throws Exception;

	public final RouteResultList getRouteResultList() {
		return this.routeResultList;
	}

	public final RouteRequest getRouteRequest() {
		return this.routeRequest;
	}

	protected RouteRankImpl(RouteRequest routeRequest) {
		this.routeRequest = routeRequest;
		this.debug(this.getProgramVersion());
	}

	private RouteRequest routeRequest;
	private RouteResultList routeResultList = new RouteResultList();

	public static RouteRank newRouteRank(RouteRequest routeRequest) throws Exception {

		RouteRankImpl routeRank ;

		if (routeRequest.getScenario() == ScenarioRandom.getScenario()) { 
			routeRank = new RouteRankImpl_Random(routeRequest);
		} else {
			routeRank = new RouteRankImpl_ScenarioPta(routeRequest);
		}

		RouteResultList routeResultList = routeRank.getRouteResultList();

		RouteResult shortest = routeRank.getRouteResult_Shortest(routeRequest);
		shortest.showDebugMessage();
		RouteResult green_01 = routeRank.getRouteResult_Green_01(routeRequest);
		green_01.showDebugMessage();
		RouteResult green_02 = routeRank.getRouteResult_Green_02(routeRequest);
		green_02.showDebugMessage();

		routeResultList.add(shortest);
		
		shortest.setIndex( 0 );

		// compare co2 and set route search type
		boolean swap = false;
		
		if ( green_01.getTotalLength_Meter() <= 0 ) {
			 swap = true;
		} else if ( green_01.getTotalCarbon_Gram() > green_02.getTotalCarbon_Gram() ) {
			 swap = true;
		}
		
		if ( swap ) {
			green_01.setRouteSearchType(RouteSearchType.GREEN_02);
			green_02.setRouteSearchType(RouteSearchType.GREEN_01);
			routeResultList.add(green_02);
			routeResultList.add(green_01);
			green_02.setIndex( 1 );
			green_01.setIndex( 2 );
		} else {
			routeResultList.add(green_01);  
			routeResultList.add(green_02);
			green_01.setIndex( 1 );
			green_02.setIndex( 2 );
		}
		// end of comparing co2 and setting route search type

		return routeRank;
	}

}
